﻿using System;
using System.Collections.Generic;

namespace SystemWnioskujacy
{
    public static class Function
    {
        static public void Print(string content)
        {
            Program.MyApp.ConsoleChildForm.Controls["ConsoleOutputBox"].Text += content;
        }

        static public void Println(string content)
        {
            Program.MyApp.ConsoleChildForm.Controls["ConsoleOutputBox"].Text += content + System.Environment.NewLine;
        }

        static public void Assert(string[] nFacts)
        {
            for (int i = 0; i < nFacts.Length; i++) Base.Add(nFacts[i]);
        }
        
        static public void Assert(string nFact)
        {
            Base.Add(nFact);
        }

        private static bool Exists(string[][] T, int x, string[] R, int b)
        {
            for (int i = 0; i < T[0].Length && i < b; i++)
            {
                for (int j = 0; j < x + 1; j++)
                {
                    if (T[j][i] != R[j]) break;
                    if (j == x) return true;
                }
            }

            return false;
        }

        private static string[] GetRow(string[][] T, int x, int j)
        {
            string[] R = new string[x + 1];

            for (int i = 0; i < R.Length; i++) R[i] = T[i][j];

            return R;
        }

        private static void Merge(ref string[][] R, string[][] nR, int x)
        {
            if (x == 0)
            {
                for (int i = 0; i < nR.Length; i++) R[i] = nR[i];
            }
            else
            {
                string[][] tR = new string[x + nR.Length][];
                for (int i = 0; i < tR.Length; i++) tR[i] = new string[0];

                for (int i = 0; i < R[x].Length; i++)
                {
                    for (int j = 0; j < nR[0].Length; j++)
                    {
                        string[] Row = GetRow(R, x, i);
                        if (nR.Length > 1)
                        {
                            if (R[x][i] == nR[0][j] && !Exists(R, x, Row, i))
                            {
                                Array.Resize(ref Row, Row.Length + nR.Length - 1);
                                for (int a = 1; a < nR.Length; a++)
                                {
                                    Row[x + a] = nR[a][j];
                                }

                                if (Exists(tR, tR.Length - 1, Row, tR[0].Length))
                                {
                                    for (int a = 0; a < tR.Length; a++)
                                    {
                                        Array.Resize(ref tR[a], tR[a].Length + 1);
                                        if (a <= x) tR[a][tR[a].Length - 1] = R[a][i];
                                        else tR[a][tR[a].Length - 1] = nR[1][j];
                                    }
                                    break;
                                }
                                for (int a = 0; a < tR.Length; a++)
                                {
                                    Array.Resize(ref tR[a], tR[a].Length + 1);
                                    if (a <= x) tR[a][tR[a].Length - 1] = R[a][i];
                                    else tR[a][tR[a].Length - 1] = nR[1][j];
                                }
                            }
                        }
                        else
                        {
                            if (!Exists(R, x, Row, i))
                            {
                                Array.Resize(ref Row, Row.Length + nR.Length - 1);
                                for (int a = 1; a < nR.Length; a++)
                                {
                                    Row[x + a] = nR[a][j];
                                }

                                if (Exists(tR, tR.Length - 1, Row, tR[0].Length))
                                {
                                    for (int a = 0; a < tR.Length; a++)
                                    {
                                        Array.Resize(ref tR[a], tR[a].Length + 1);
                                        if (a <= x) tR[a][tR[a].Length - 1] = R[a][i];
                                        else tR[a][tR[a].Length - 1] = nR[1][j];
                                    }
                                    break;
                                }
                                for (int a = 0; a < tR.Length; a++)
                                {
                                    Array.Resize(ref tR[a], tR[a].Length + 1);
                                    if (a <= x) tR[a][tR[a].Length - 1] = R[a][i];
                                    else tR[a][tR[a].Length - 1] = nR[1][j];
                                }
                            }
                        }
                    }
                }

                R = tR;
            }
        }

        static public void Assert(Query nQuery, Rule S)
        {
            string[][] R = new string[nQuery.Length][];
            bool Found = false;

            for (int i = 0; i < nQuery.Length; i++)
            {
                if (!nQuery[i].IsVar)
                {
                    if (i == 0)
                    {
                        if (nQuery.Length > 1)
                        {
                            R[0] = new string[nQuery[1].Length];
                            R[1] = new string[nQuery[1].Length];
                            for (int j = 0; j < nQuery[1].Length; j++)
                            {
                                R[0][j] = nQuery[0][0];
                                R[1][j] = nQuery[1][j];
                            }
                        }
                        else R[0] = new string[1] { nQuery[0][0] };
                    }
                    else
                    {
                        if (R[i] == null) R[i] = new string[R[i - 1].Length];

                        for (int j = i + 1; j < R[i].Length; j++) R[i][j] = nQuery[i][0];
                    }
                }
                else
                {
                    for (int j = i + 1; j < nQuery.Length; j++)
                    {
                        if (nQuery[j].IsVar)
                        {
                            Found = true;

                            Query Q1 = new Query();
                            Query Q2 = new Query();
                            Q1.IDs = nQuery[i].IDs;
                            Q2.IDs = nQuery[j].IDs;

                            int D;
                            if (S.VD.Distance(nQuery[i], nQuery[j], out D) && D != 0)
                            {
                                string[][] tR = Base.FactsBase.Results(Q1, Q2, nQuery[i], nQuery[j], D);
                                Merge(ref R, tR, i);
                            }
                        }
                    }

                    if (!Found) Merge(ref R, new string[1][] {nQuery[i].Get()}, i);
                }
            }
            /*
            for (int a = 0, b = 1; b < nQuery.Length; a++, b++)
            {
                if (!nQuery[a].IsVar || !nQuery[b].IsVar) continue;
                Query Q1 = new Query();
                Query Q2 = new Query();
                Q1.IDs = nQuery[a].IDs;
                Q2.IDs = nQuery[b].IDs;

                int D;
                if (S.VD.Distance(nQuery[a], nQuery[b], out D) && D > 0)
                {
                    string[][] tR = Base.FactsBase.Results(Q1, Q2, nQuery[a], nQuery[b], D);
                    Merge(ref R, tR, a);
                }

                //string[][] tR = Base.FactsBase.Results(Q1, Q2, nQuery[a], nQuery[b], 1);
                //Merge(ref R, tR, a);
            }
            */
            if (R.Length != 0 && R[0].Length != 0)
            {
                for (int i = 0; i < R[0].Length; i++)
                {
                    string F = R[0][i];

                    for (int j = 1; j < R.Length; j++)
                    {
                        F += " " + R[j][i];
                    }

                    Base.Add(F, S.n_grf, S.irf * S.n_irf);
                }
            }
        }

        static public void DeAssert(string Fact)
        {
            Base.Remove(Fact);
        }

        static public void DeAssert(int ID) {
            Base.Remove(ID);
        }

        static public void Facts()
        {
            List<string> AllFacts = Base.FactsBase.GetAll();

            for (int i = 0; i < AllFacts.Count; i++)
            {
                if (AllFacts[i] != String.Empty) Println("Fact ID: " + Base.FactsBase.GetID(AllFacts[i]) + " = \"" + AllFacts[i] + "\" with grf = " + String.Format("{0:0.##}", Base.Get_GRF(AllFacts[i])) + " and irf = " + String.Format("{0:0.##}", Base.Get_IRF(AllFacts[i])) + ".");
            }

            // Wyświetla liczbę faktów
            Println(string.Format("\nFacts number:\t{0}\n", (AllFacts != null) ? AllFacts.Count.ToString() : "0"));
        }

        static public void Rules()
        {
            for (int i = 0; i < Base.RulesBase.rTab.Length; i++)
            {
                Println("Rule ID: " + i + " Name = \"" + Base.RulesBase.rTab[i].Name + "\" with grf = " + Base.RulesBase.rTab[i].grf + " and irf = " + Base.RulesBase.rTab[i].irf + ".");
            }

            // Wyświetla liczbę reguł
            Println(string.Format("\nRules number:\t{0}\n", (Base.RulesBase != null && Base.RulesBase.rTab != null) ? Base.RulesBase.rTab.Length.ToString() : "0"));
        }

        static public void DefRule(Rule nRule)
        {
            Base.RulesBase.Add(nRule);
        }

        static public void InitEnv(double pr1, double pr2, double t) {
            Base.RulesBase.r1 = pr1;
            Base.RulesBase.r2 = pr2;
            Base.RulesBase.t = t;
        }

        static public void EnvInfo() {
            Println(string.Format("\nEnvironment info\n\tTreshold 1: {0:0.##}\n\tTreshold 2: {1:0.##}\n\tRatio of the coefficients: {2:0.##}", Base.RulesBase.r1, Base.RulesBase.r2, Base.RulesBase.t));
        }

        static public void Run()
        {
            Base.RulesBase.Run2();
        }

        static public void Clear()
        {
            Base.Clear();
            ClearScreen();
        }

        static public void ClearScreen() {
            Program.MyApp.ConsoleChildForm.Controls["ConsoleOutputBox"].Text = "";
            Program.MyApp.ConsoleChildForm.Controls["ConsoleOutputBox"].Invalidate();
        }

        static public bool Quit(bool quitCommand = false) {
            bool exit = false;

            if (quitCommand) {
                Program.MyApp.exitFromConsole = true;
                exit = true;
                Clear();
                Program.MyApp.Close();
            }
            else {
                System.Windows.Forms.DialogResult res = System.Windows.Forms.MessageBox.Show(
                    Resources.Common.Quit_Question,
                    Resources.Common.Quit_Title,
                    System.Windows.Forms.MessageBoxButtons.YesNo,
                    System.Windows.Forms.MessageBoxIcon.Question
                    );
                exit = (res == System.Windows.Forms.DialogResult.Yes) ? true : false;
            }

            return exit;
        }

        static public void RunWithoutUncertainty() {
            Base.RulesBase.Run();
        }
    }
}
